package impl

import (
	"context"
	"fmt"
	"time"

	"gitee.com/hexug/devcloud/mcenter/apps/user"
	"gitee.com/hexug/devcloud/mcenter/common/validate"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo/options"
)

func (i *implServer) CreateUser(ctx context.Context, in *user.CreateUserRequest) (*user.User, error) {
	//校验数据
	if err := validate.V().Struct(in); err != nil {
		return nil, err
	}
	u := user.NewUser(in)
	if err := u.HashPassword(); err != nil {
		return nil, err
	}
	_, err := i.Col.InsertOne(ctx, u)
	if err != nil {
		return nil, err
	}
	u.Desensitize()
	return u, nil
}
func (i *implServer) UpdateUser(ctx context.Context, in *user.UpdateUserRequest) (*user.User, error) {
	//校验数据
	if err := validate.V().Struct(in); err != nil {
		return nil, err
	}
	filter := bson.M{"_id": in.Id}
	var update bson.D
	dur := user.NewDetailUserRequestById(in.Id)
	u1, err := i.DetailUser(ctx, dur)
	if err != nil {
		return nil, err
	}
	//是否相同
	flag1 := true
	//是否有参数
	flag2 := false
	if in.Domain != "" {
		flag2 = true
		if in.Domain != u1.Spec.Domain {
			flag1 = false
			update = append(update, bson.E{Key: "$set", Value: bson.D{{Key: "domain", Value: in.Domain}}})
		}
	}
	if in.Username != "" {
		flag2 = true
		if in.Username != u1.Spec.Username {
			flag1 = false
			update = append(update, bson.E{Key: "$set", Value: bson.D{{Key: "username", Value: in.Username}}})
		}
	}
	if in.Password != "" {
		flag2 = true
		if err := u1.CheckPassword(in.Password); err != nil {
			flag1 = false
			passwd, err := user.HashPassword(in.Password)
			if err != nil {
				return nil, err
			}
			update = append(update, bson.E{Key: "$set", Value: bson.D{{Key: "password", Value: passwd}}})
		}
	}
	if flag2 && flag1 {
		return nil, fmt.Errorf("与原数据相同,无需修改")
	}
	if update == nil {
		return nil, fmt.Errorf("参数不足！")
	}
	//更新更新时间
	now := time.Now().Unix()
	update = append(update, bson.E{Key: "$set", Value: bson.M{"updated_at": now}})
	if _, err := i.Col.UpdateOne(ctx, filter, update); err != nil {
		return nil, err
	}
	//用ID查询出用户
	dr := user.NewDetailUserRequestById(in.Id)
	u, err := i.DetailUser(ctx, dr)
	if err != nil {
		return nil, err
	}
	return u, nil
}

// 查询用户列表
func (i *implServer) QueryUser(ctx context.Context, in *user.QueryUserRequest) (*user.UserSet, error) {
	//校验数据
	if err := validate.V().Struct(in); err != nil {
		return nil, err
	}
	//防止过度获取
	if in.PageSize <= 0 || in.PageSize > 30 {
		in.PageSize = 5
	}
	if in.PageNumber <= 0 || in.PageNumber > 10 {
		in.PageNumber = 1
	}
	// fmt.Println(in)
	var filter bson.M
	//按创建时间倒排
	opt := options.Find().
		SetLimit(in.PageSize).
		SetSkip((in.PageNumber - 1) * in.PageSize).
		SetSort(bson.D{{Key: "created_at", Value: -1}}) //按创建时间倒序取出
	if in.Keyword != "" {
		filter = bson.M{"username": bson.M{"$regex": in.Keyword, "$options": "im"}}
	}
	cursor, err := i.Col.Find(ctx, filter, opt)
	if err != nil {
		return nil, err
	}
	d := user.NewUserSet()
	if err := cursor.All(ctx, &d.Items); err != nil {
		return nil, err
	}
	for _, us := range d.Items {
		us.Desensitize()
	}
	count, err := i.Col.CountDocuments(ctx, filter)
	if err != nil {
		return nil, err
	}
	d.Total = count
	return d, nil
}

// 默认使用id查询，查询为其他方式也使用id查询
func (i *implServer) DetailUser(ctx context.Context, in *user.DetailUserRequest) (*user.User, error) {
	//校验数据
	if err := validate.V().Struct(in); err != nil {
		return nil, err
	}
	filter := bson.M{"_id": in.Value}
	if in.DetailType == user.DESCRIBE_BY_USERNAME {
		filter = bson.M{"username": in.Value}
	}
	res := i.Col.FindOne(ctx, filter)
	if res.Err() != nil {
		return nil, res.Err()
	}
	u := &user.User{}
	if err := res.Decode(u); err != nil {
		return nil, err
	}
	return u, nil
}
func (i *implServer) DeleteUser(ctx context.Context, in *user.DeleteUserRequest) (*user.User, error) {
	//校验数据
	if err := validate.V().Struct(in); err != nil {
		return nil, err
	}
	filter := bson.M{"_id": in.Value}
	if in.DetailType == user.DESCRIBE_BY_USERNAME {
		filter = bson.M{"username": in.Value}
	}
	u := &user.User{}
	res := i.Col.FindOneAndDelete(ctx, filter)
	if res.Err() != nil {
		return nil, res.Err()
	}
	if err := res.Decode(u); err != nil {
		return nil, err
	}
	//脱敏
	u.Desensitize()
	return u, nil
}
